<?php
declare (strict_types=1);

namespace app\common\model;

use app\common\model\ModuleField as ModuleFieldModel;
use think\Collection;
use Exception;

class Article extends CommonBase
{
    public function __construct(array $data = [], string $connection = 'mysql', string $name = '')
    {
        parent::__construct($data);
        $this->connection = $connection;
        $this->name       = $name;
    }

    public function getArticleList(int $page = 1, int $limit = 10, array $where = [], array $order = ['p.sort', 'p.created_at' => 'desc'], string $attribute = ''): Collection
    {
        if (empty($attribute)) {
            $where['is_delete'] = config('status.mysql.table_normal');
            $offset             = ($page - 1) * $limit;
            return $this->alias('p')->where($where)->order($order)->limit($offset, $limit)->select();
        }

        // 有属性筛选
        $dbPrefix   = config('database.connections.' . $this->connection . '.prefix');
        $db         = $this->name($this->name)->alias('p')->field('p.*');
        $attributes = explode(',', $attribute);
        foreach ($attributes as $attribute) {
            $values = explode(':', $attribute);
            if (!count($values) || count($values) <= 1) {
                continue;
            }

            $attributeId      = intval($values[0]);
            $attributeValueId = intval($values[1]);
            $alias            = 'a' . $attributeId;
            $t                = $dbPrefix . $this->name . '_relation_attribute ' . $alias;
            $db               = $db->Join($t, $alias . '.aid = p.id and '
                . $alias . '.attribute_id=' . $attributeId . ' and '
                . $alias . '.attribute_value_id=' . $attributeValueId . ' and '
                . $alias . '.is_delete=' . config('status.mysql.table_normal'));
        }

        $where['p.is_delete'] = config('status.mysql.table_normal');
        $offset               = ($page - 1) * $limit;
        return $db->where($where)->order($order)->limit($offset, $limit)->select();
    }

    public function getArticleCount(array $where = [], string $attribute = ''): int
    {
        if (empty($attribute)) {
            $where['is_delete'] = config('status.mysql.table_normal');
            return $this->alias('p')->where($where)->count();
        }

        // 有属性筛选
        $dbPrefix   = config('database.connections.' . $this->connection . '.prefix');
        $db         = $this->name($this->name)->alias('p');
        $attributes = explode(',', $attribute);
        foreach ($attributes as $attribute) {
            $values = explode(':', $attribute);
            if (!count($values) || count($values) <= 1) {
                continue;
            }

            $attributeId      = intval($values[0]);
            $attributeValueId = intval($values[1]);
            $alias            = 'a' . $attributeId;
            $t                = $dbPrefix . $this->name . '_relation_attribute ' . $alias;
            $db               = $db->Join($t, $alias . '.aid = p.id and '
                . $alias . '.attribute_id=' . $attributeId . ' and '
                . $alias . '.attribute_value_id=' . $attributeValueId . ' and '
                . $alias . '.is_delete=' . config('status.mysql.table_normal'));
        }

        $where['p.is_delete'] = config('status.mysql.table_normal');
        return $db->where($where)->count();
    }

    /**
     * @throws Exception
     */
    public function addArticle(string $cdnDomain, array $data): bool
    {
        $createdAt = $data['created_at'];
        $updatedAt = date('Y-m-d H:i:s');
        try {
            $this->startTrans();
            // 主表
            $articleData = [
                'category_id'      => $data['category_id'],
                'title'            => $data['title'],
                'sort'             => $data['sort'],
                'meta_title'       => $data['meta_title'],
                'meta_keyword'     => $data['meta_keyword'],
                'meta_description' => $data['meta_description'],
                'status'           => $data['status'],
                'image'            => $data['image'],
                'hit'              => $data['hit'],
                'created_at'       => $createdAt,
                'updated_at'       => $updatedAt,
                'is_delete'        => config('status.mysql.table_normal'),
            ];
            $this->insert($articleData);
            $articleId = $this->getLastInsID();

            // 图集
            // 有属性的图集
            $imageTableName = $this->name . '_image';
            if ($data['has_image_attribute']) {
                $attributeValues  = $data['image_attribute']['attribute_values'] ?? [];
                $imageAttributeId = $data['image_attribute']['attribute_id'] ?? 0;

                $attributeValueIds = [];
                foreach ($attributeValues as $attributeValue) {
                    $attributeValueIds[] = $attributeValue['attribute_value_id'];
                }

                if ($imageAttributeId) {
                    $data['attributes'][] = [
                        'attribute_id'        => $imageAttributeId,
                        'attribute_value_ids' => $attributeValueIds,
                    ];
                }

                foreach ($attributeValues as $attributeValue) {

                    $insertImageData = [
                        'aid'                => $articleId,
                        'attribute_value_id' => $attributeValue['attribute_value_id'],
                    ];
                    foreach ($attributeValue['images'] as $image) {
                        $this->name($imageTableName)->insert(
                            array_merge(
                                $insertImageData,
                                [
                                    'title'      => $image['title'],
                                    'image'      => $image['image'],
                                    'created_at' => $createdAt,
                                    'updated_at' => $updatedAt,
                                    'is_delete'  => config('status.mysql.table_normal'),
                                ])
                        );
                    }
                }
            } else {
                foreach ($data['images'] as $image) {
                    $this->name($imageTableName)->insert([
                        'aid'        => $articleId,
                        'title'      => $image['title'],
                        'image'      => $image['image'],
                        'created_at' => $createdAt,
                        'updated_at' => $updatedAt,
                        'is_delete'  => config('status.mysql.table_normal'),
                    ]);
                }
            }

            // 其他字段
            $articleFields = (new ModuleFieldModel([], $this->connection))->getArticleFields($data['category_id']);
            foreach ($data['extend_fields'] as $field) {
                if (!isset($articleFields[$field['code']])) {
                    continue;
                }

                $articleField    = $articleFields[$field['code']];
                $extendTableName = $this->name . '_' . self::FIELD_TYPE_DB_SUFFIX_MAP[$articleField['field_type']];

                $fieldValue = $field['value'];
                if ($articleField['field_type'] == 'editor') {
                    $fieldValue = str_replace($cdnDomain, '{{cdn_domain}}', $fieldValue);
                }

                $this->name($extendTableName)->insert([
                    'aid'         => $articleId,
                    'field_id'    => $articleField['id'],
                    'field_value' => $fieldValue,
                    'created_at'  => $createdAt,
                    'updated_at'  => $updatedAt,
                    'is_delete'   => config('status.mysql.table_normal'),
                ]);
            }

            // dump($data['attributes']);exit;
            // 属性
            $relationAttributeTableName = $this->name . '_relation_attribute';
            foreach ($data['attributes'] as $attribute) {
                foreach ($attribute['attribute_value_ids'] as $attributeValueId) {
                    $this->name($relationAttributeTableName)->insert([
                        'aid'                => $articleId,
                        'attribute_id'       => $attribute['attribute_id'],
                        'attribute_value_id' => $attributeValueId,
                        'created_at'         => $createdAt,
                        'updated_at'         => $updatedAt,
                        'is_delete'          => config('status.mysql.table_normal'),
                    ]);
                }
            }

            if (!empty($data['image'])) {
                $this->name('attachment')->where(['url_md5' => md5($data['image'])])->update([
                    'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                    'relation_id'   => $articleId,
                    'updated_at'    => date('Y-m-d H:i:s'),
                ]);
            }

            foreach ($data['images'] as $image) {
                $this->name('attachment')->where(['url_md5' => md5($image['image'])])->update([
                    'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                    'relation_id'   => $articleId,
                    'updated_at'    => date('Y-m-d H:i:s'),
                ]);
            }

            $dom = new \DOMDocument();

            foreach ($data['extend_fields'] as $field) {
                $fieldValue   = $field['value'];
                $articleField = $articleFields[$field['code']];
                if ($articleField['field_type'] == 'image' || $articleField['field_type'] == 'file') {
                    if (!empty($fieldValue)) {
                        $this->name('attachment')->where(['url_md5' => md5($fieldValue)])->update([
                            'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                            'relation_id'   => $articleId,
                            'updated_at'    => date('Y-m-d H:i:s'),
                        ]);
                    }
                }

                if ($articleField['field_type'] == 'editor' && !empty($fieldValue)) {
                    libxml_use_internal_errors(true);
                    $dom->loadHTML($fieldValue);
                    libxml_use_internal_errors(false);
                    $xpath   = new \DOMXPath($dom);
                    $imgTags = $xpath->query('//img');

                    foreach ($imgTags as $imgTag) {
                        $src = ltrim($imgTag->getAttribute('src'), $cdnDomain . '/');
                        $this->name('attachment')->where(['url_md5' => md5($src)])->update([
                            'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                            'relation_id'   => $articleId,
                            'updated_at'    => date('Y-m-d H:i:s'),
                        ]);
                    }
                }
            }

            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    public function findLastArticleSortByCategoryId(int $categoryId): array
    {
        $article    = [];
        $articleOne = $this->where(['category_id' => $categoryId, 'is_delete' => config('status.mysql.table_normal')])->order('sort desc')->find();
        if (empty($articleOne)) {
            return $article;
        }

        return $articleOne->toArray();
    }

    public function findArticleWithoutExtendFieldsById(int $id): array
    {
        $article    = [];
        $articleOne = $this->where(['id' => $id, 'is_delete' => config('status.mysql.table_normal')])->find();
        if (empty($articleOne)) {
            return $article;
        }

        return $articleOne->toArray();
    }

    public function findArticleById(string $cdnDomain, int $id, array $categories): array
    {
        $article = [];

        // 主表数据
        $articleOne = $this->where(['id' => $id, 'is_delete' => config('status.mysql.table_normal')])->find();
        if (empty($articleOne)) {
            return $article;
        }
        $article              = $articleOne->toArray();
        $article['fullImage'] = $article['image'] ? $cdnDomain . '/' . $article['image'] : '';
        $category             = $categories[$article['category_id']];
        // dump($category);exit;
        $article['category']  = $category;

        // 扩展数据
        $moduleFieldModel  = new ModuleFieldModel([], $this->connection);
        $articleFields     = $moduleFieldModel->getArticleFields($category['id']);
        $extendFieldDetail = [];
        foreach ($articleFields as $articleField) {
            $fieldValue = $article[$articleField['code']] ?? '';
            if ($articleField['is_system'] == self::FIELD_IS_CUSTOMER) {
                $extendTableName = $this->name . '_' . self::FIELD_TYPE_DB_SUFFIX_MAP[$articleField['field_type']];
                $extendOneObj    = $this->name($extendTableName)->where([
                    'aid'       => $article['id'],
                    'field_id'  => $articleField['id'],
                    'is_delete' => config('status.mysql.table_normal'),
                ])->find();
                if (!empty($extendOneObj)) {
                    $extendOne  = $extendOneObj->toArray();
                    $fieldValue = $extendOne['field_value'];
                }
            }

            $fullFieldValue = $fieldValue;
            if ($articleField['field_type'] == 'image' || $articleField['field_type'] == 'file') {
                $fullFieldValue = $fullFieldValue ? $cdnDomain . '/' . $fullFieldValue : '';
            }

            if ($articleField['field_type'] == 'editor') {
                $fullFieldValue = str_replace('{{cdn_domain}}', $cdnDomain, $fullFieldValue);
                $fieldValue     = $fullFieldValue;
            }

            $extendFieldDetail[$articleField['code']] = [
                'code'           => $articleField['code'],
                'field_value'    => $fieldValue,
                'fullFieldValue' => $fullFieldValue,
                'field_type'     => $articleField['field_type'],
                'field_id'       => $articleField['id'],
                'is_system'      => $articleField['is_system'],
                'is_require'     => $articleField['is_require'],
                'name'           => $articleField['name']
            ];
        }

        $article['extend_fields'] = $extendFieldDetail;
        $extendFieldMap           = [];
        foreach ($extendFieldDetail as $extendsField) {
            $extendFieldMap[$extendsField['code']] = $extendsField['field_value'];
            if ($extendsField['field_type'] === 'image' || $extendsField['field_type'] === 'file') {
                $extendFieldMap[underScoreToCamelCase('full_' . $extendsField['code'])] = $extendsField['fullFieldValue'];
            }

            if ($extendsField['field_type'] == 'editor') {
                $extendFieldMap[$extendsField['code']] = str_replace('{{cdn_domain}}', $cdnDomain, $extendsField['field_value']);
            }
        }
        $article['ext_fields'] = $extendFieldMap;

        // 图集
        $imageTableName = $this->name . '_image';
        $articleImages  = $this->name($imageTableName)->where(['aid' => $article['id'], 'is_delete' => config('status.mysql.table_normal')])->select()->toArray();
        foreach ($articleImages as $k => $articleImage) {
            $articleImages[$k]['fullImage'] = $articleImage['image'] ? $cdnDomain . '/' . $articleImage['image'] : '';
        }
        $article['images'] = $articleImages;

        // 有属性的图集
        $articleImageAttribute = [
            'attribute_id'     => 0,
            'name'             => '',
            'options'          => [],
            'attribute_values' => [],
        ];

        // 每个属性值的图集
        $articleImageAttributeValues = [];
        if ($category['hasImageAttribute']) {
            $articleAttributeValueImageMap = [];
            foreach ($articleImages as $articleImage) {
                $articleAttributeValueImageMap[$articleImage['attribute_value_id']][] = $articleImage;
            }

            foreach ($articleAttributeValueImageMap as $attributeValueId => $images) {
                $articleImageAttributeValues[$attributeValueId] = [
                    'attribute_value_id' => $attributeValueId,
                    'images'             => $images,
                ];
            }

            //  每个属性值的图集
            $articleImageAttribute['attribute_values'] = array_values($articleImageAttributeValues);
        }

        // 文档的属性数据
        $articleNormalAttributes    = [];
        $relationAttributeTableName = $this->name . '_relation_attribute';
        $articleRelationAttributes  = $this->name($relationAttributeTableName)->where(['aid' => $article['id'], 'is_delete' => config('status.mysql.table_normal')])->select()->toArray();

        $articleAttributeMap = [];
        foreach ($articleRelationAttributes as $articleRelationAttribute) {
            $articleAttributeMap[$articleRelationAttribute['attribute_id']] [] = $articleRelationAttribute['attribute_value_id'];
        }

        // dump($category['attributes']);

        foreach ($articleRelationAttributes as $articleRelationAttribute) {
            $attributeId = $articleRelationAttribute['attribute_id'];
            if (isset($articleImageAttributeValues[$articleRelationAttribute['attribute_value_id']])) {
                $articleImageAttribute['attribute_id'] = $attributeId;
                $articleImageAttribute['name']         = $category['attributes'][$attributeId]['name'];
                $articleImageAttribute['options']      = $category['attributes'][$attributeId]['values'];
            }


            $articleNormalAttributes[$attributeId] = [
                'attribute_id'       => $attributeId,
                'name'               => $category['attributes'][$attributeId]['name'],
                'options'            => $category['attributes'][$attributeId]['values'],
                'attribute_value_id' => $articleAttributeMap[$attributeId],
            ];
        }

        $article['image_attribute'] = $articleImageAttribute;

        $article['normal_attributes'] = [];
        foreach ($category['attributes'] as $attribute) {
            $attributeId = $attribute['id'];
            if (isset($articleNormalAttributes[$attributeId]) && $attributeId != $category['imageAttributeId']) {
                $article['normal_attributes'][] = $articleNormalAttributes[$attributeId];
            }
        }

        return $article;
    }

    public function getArticleListExtendFields(string $cdnDomain, array $ids, int $categoryId): array
    {
        $extendFieldDetail = [];

        $moduleFieldModel = new ModuleFieldModel([], $this->connection);
        $articleFields    = $moduleFieldModel->getArticleFields($categoryId);

        foreach ($articleFields as $articleField) {
            if ($articleField['show_list'] != self::FIELD_IS_SHOW_LIST) {
                continue;
            }

            if ($articleField['is_system'] != self::FIELD_IS_CUSTOMER) {
                continue;
            }

            $fieldValues     = [];
            $extendTableName = $this->name . '_' . self::FIELD_TYPE_DB_SUFFIX_MAP[$articleField['field_type']];
            $extendObj       = $this->name($extendTableName)->where([
                ['aid', 'in', $ids],
                'field_id'  => $articleField['id'],
                'is_delete' => config('status.mysql.table_normal'),
            ])->select()->toArray();

            if (!empty($extendObj)) {
                foreach ($extendObj as $extend) {
                    $fieldValues[$extend['aid']] = $extend['field_value'];
                }
            }

            foreach ($ids as $id) {
                $fieldValue     = $fieldValues[$id] ?? '';
                $fullFieldValue = $fieldValue;
                if ($articleField['field_type'] == 'image' || $articleField['field_type'] == 'file') {
                    $fullFieldValue = $cdnDomain . '/' . $fieldValue;
                }
                $extendFieldDetail[$id][$articleField['code']] = [
                    'code'           => $articleField['code'],
                    'field_value'    => $fieldValue,
                    'fullFieldValue' => $fullFieldValue,
                    'field_type'     => $articleField['field_type'],
                    'field_id'       => $articleField['id'],
                    'is_system'      => $articleField['is_system'],
                    'is_require'     => $articleField['is_require'],
                    'name'           => $articleField['name']
                ];
            }
        }

        return $extendFieldDetail;
    }

    /**
     * @throws Exception
     */
    public function updateArticle(string $cdnDomain, int $id, array $data): bool
    {
        try {
            $this->startTrans();
            $updatedAt = date('Y-m-d H:i:s');
            // 主表
            $articleData = [
                'category_id'      => $data['category_id'],
                'title'            => $data['title'],
                'sort'             => $data['sort'],
                'meta_title'       => $data['meta_title'],
                'meta_keyword'     => $data['meta_keyword'],
                'meta_description' => $data['meta_description'],
                'status'           => $data['status'],
                'image'            => $data['image'],
                'hit'              => $data['hit'],
                'updated_at'       => $updatedAt,
                'is_delete'        => config('status.mysql.table_normal'),
            ];
            $this->where(['id' => $id])->update($articleData);
            $articleId = $id;

            // 图集
            // 有属性的图集
            $imageTableName = $this->name . '_image';
            $this->name($imageTableName)
                ->where(['aid' => $articleId])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            if ($data['has_image_attribute']) {
                $attributeValues  = $data['image_attribute']['attribute_values'] ?? [];
                $imageAttributeId = $data['image_attribute']['attribute_id'] ?? 0;

                $attributeValueIds = [];
                foreach ($attributeValues as $attributeValue) {
                    $attributeValueIds[] = $attributeValue['attribute_value_id'];
                }

                if ($imageAttributeId) {
                    $data['attributes'][] = [
                        'attribute_id'        => $imageAttributeId,
                        'attribute_value_ids' => $attributeValueIds,
                    ];
                }


                foreach ($attributeValues as $attributeValue) {
                    $insertImageData = [
                        'aid'                => $articleId,
                        'attribute_value_id' => $attributeValue['attribute_value_id'],
                    ];
                    foreach ($attributeValue['images'] as $image) {
                        $this->name($imageTableName)->insert(
                            array_merge(
                                $insertImageData,
                                [
                                    'title'      => $image['title'],
                                    'image'      => $image['image'],
                                    'created_at' => $data['created_at'],
                                    'updated_at' => $updatedAt,
                                    'is_delete'  => config('status.mysql.table_normal'),
                                ])
                        );
                    }
                }
            } else {
                foreach ($data['images'] as $image) {
                    $this->name($imageTableName)->insert([
                        'aid'        => $articleId,
                        'title'      => $image['title'],
                        'image'      => $image['image'],
                        'created_at' => $data['created_at'],
                        'updated_at' => $updatedAt,
                        'is_delete'  => config('status.mysql.table_normal'),
                    ]);
                }
            }

            // 其他字段
            $articleFields = (new ModuleFieldModel([], $this->connection))->getArticleFields($data['category_id']);
            foreach ($data['extend_fields'] as $field) {
                if (!isset($articleFields[$field['code']])) {
                    continue;
                }

                $articleField    = $articleFields[$field['code']];
                $extendTableName = $this->name . '_' . self::FIELD_TYPE_DB_SUFFIX_MAP[$articleField['field_type']];
                $this->name($extendTableName)
                    ->where(['aid' => $articleId, 'field_id' => $articleField['id']])
                    ->update([
                        'updated_at' => $updatedAt,
                        'is_delete'  => config('status.mysql.table_delete'),
                    ]);

                $fieldValue = $field['value'];
                if ($articleField['field_type'] == 'editor') {
                    $fieldValue = str_replace($cdnDomain, '{{cdn_domain}}', $fieldValue);
                }

                $this->name($extendTableName)->insert([
                    'aid'         => $articleId,
                    'field_id'    => $articleField['id'],
                    'field_value' => $fieldValue,
                    'created_at'  => $data['created_at'],
                    'updated_at'  => $updatedAt,
                    'is_delete'   => config('status.mysql.table_normal'),
                ]);
            }

            // dump($data['attributes']);exit;
            // 属性
            $relationAttributeTableName = $this->name . '_relation_attribute';
            $this->name($relationAttributeTableName)
                ->where(['aid' => $articleId])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            foreach ($data['attributes'] as $attribute) {
                foreach ($attribute['attribute_value_ids'] as $attributeValueId) {
                    $this->name($relationAttributeTableName)->insert([
                        'aid'                => $articleId,
                        'attribute_id'       => $attribute['attribute_id'],
                        'attribute_value_id' => $attributeValueId,
                        'created_at'         => $data['created_at'],
                        'updated_at'         => $updatedAt,
                        'is_delete'          => config('status.mysql.table_normal'),
                    ]);
                }
            }

            if (!empty($data['image'])) {
                $this->name('attachment')->where(['url_md5' => md5($data['image'])])->update([
                    'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                    'relation_id'   => $articleId,
                    'updated_at'    => date('Y-m-d H:i:s'),
                ]);
            }

            foreach ($data['images'] as $image) {
                $this->name('attachment')->where(['url_md5' => md5($image['image'])])->update([
                    'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                    'relation_id'   => $articleId,
                    'updated_at'    => date('Y-m-d H:i:s'),
                ]);
            }

            $dom = new \DOMDocument();
            foreach ($data['extend_fields'] as $field) {
                $fieldValue   = $field['value'];
                $articleField = $articleFields[$field['code']];
                if ($articleField['field_type'] == 'image' || $articleField['field_type'] == 'file') {
                    if (!empty($fieldValue)) {
                        $this->name('attachment')->where(['url_md5' => md5($fieldValue)])->update([
                            'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                            'relation_id'   => $articleId,
                            'updated_at'    => date('Y-m-d H:i:s'),
                        ]);
                    }
                }

                if ($articleField['field_type'] == 'editor' && !empty($fieldValue)) {
                    libxml_use_internal_errors(true);
                    $dom->loadHTML($fieldValue);
                    libxml_use_internal_errors(false);
                    $xpath   = new \DOMXPath($dom);
                    $imgTags = $xpath->query('//img');

                    foreach ($imgTags as $imgTag) {
                        $src = ltrim($imgTag->getAttribute('src'), $cdnDomain . '/');
                        $this->name('attachment')->where(['url_md5' => md5($src)])->update([
                            'relation_type' => self::ARTICLE_ATTACHMENT_TYPE,
                            'relation_id'   => $articleId,
                            'updated_at'    => date('Y-m-d H:i:s'),
                        ]);
                    }
                }
            }

            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    /**
     * @throws Exception
     */
    public function deleteArticle(int $id, array $fields): bool
    {
        try {
            $this->startTrans();
            $updatedAt = date('Y-m-d H:i:s');
            $articleId = $id;

            // 主表
            $this->where(['id' => $id])->update([
                'updated_at' => $updatedAt,
                'is_delete'  => config('status.mysql.table_delete')
            ]);

            // 扩展表
            foreach ($fields as $field) {
                if ($field['is_system'] != self::FIELD_IS_SYSTEM) {
                    continue;
                }

                $extendTableName = $this->name . '_' . self::FIELD_TYPE_DB_SUFFIX_MAP[$field['field_type']];
                $this->name($extendTableName)
                    ->where(['aid' => $articleId])
                    ->update([
                        'updated_at' => $updatedAt,
                        'is_delete'  => config('status.mysql.table_delete'),
                    ]);
            }

            // 图集
            $imageTableName = $this->name . '_image';
            $this->name($imageTableName)
                ->where(['aid' => $articleId])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            // 属性
            $relationAttributeTableName = $this->name . '_relation_attribute';
            $this->name($relationAttributeTableName)
                ->where(['aid' => $articleId])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            // 文档标签
            $articleFlagTableName = $this->name . '_flag';
            $this->name($articleFlagTableName)
                ->where(['aid' => $articleId])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            $this->name('attachment')->where(['relation_id' => $id, 'relation_type' => self::ARTICLE_ATTACHMENT_TYPE])->update([
                'is_delete'  => config('status.mysql.table_delete'),
                'updated_at' => date('Y-m-d H:i:s'),
            ]);

            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    /**
     * @throws Exception
     */
    public function batchArticleSort(array $data): bool
    {
        $this->startTrans();
        try {
            foreach ($data as $id => $sort) {
                $this->where('id', $id)->update(['sort' => $sort]);
            }
            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    /**
     * @throws Exception
     */
    public function batchDeleteArticle(array $ids, array $fields): bool
    {
        try {
            $this->startTrans();
            $updatedAt = date('Y-m-d H:i:s');
            // 主表
            $this->where([['id', 'in', $ids]])->save([
                'is_delete'  => config('status.mysql.table_delete'),
                'updated_at' => date('Y-m-d H:i:s'),
            ]);

            // 扩展表
            foreach ($fields as $field) {
                if ($field['is_system'] != self::FIELD_IS_SYSTEM) {
                    continue;
                }

                $extendTableName = $this->name . '_' . self::FIELD_TYPE_DB_SUFFIX_MAP[$field['field_type']];
                $this->name($extendTableName)
                    ->where([['aid', 'in', $ids]])
                    ->update([
                        'updated_at' => $updatedAt,
                        'is_delete'  => config('status.mysql.table_delete'),
                    ]);
            }

            // 图集
            $imageTableName = $this->name . '_image';
            $this->name($imageTableName)
                ->where([['aid', 'in', $ids]])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            // 属性
            $relationAttributeTableName = $this->name . '_relation_attribute';
            $this->name($relationAttributeTableName)
                ->where([['aid', 'in', $ids]])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            // 文档标签
            $articleFlagTableName = $this->name . '_flag';
            $this->name($articleFlagTableName)
                ->where([['aid', 'in', $ids]])
                ->update([
                    'updated_at' => $updatedAt,
                    'is_delete'  => config('status.mysql.table_delete'),
                ]);

            $this->name('attachment')->where([['relation_id', 'in', $ids], 'relation_type' => self::ARTICLE_ATTACHMENT_TYPE])->update([
                'is_delete'  => config('status.mysql.table_delete'),
                'updated_at' => date('Y-m-d H:i:s'),
            ]);

            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    public function batchUpdateArticleStatus(array $ids, int $status): bool
    {
        return (boolean)$this->where([['id', 'in', $ids]])->save(['status' => $status, 'updated_at' => date('Y-m-d H:i:s')]);
    }

    public function getFlagIdByArticleIds(array $articleIds): Collection
    {
        $tableName = $this->name . '_flag';
        return $this->name($tableName)->where([
            ['aid', 'in', $articleIds],
            'is_delete' => config('status.mysql.table_normal')])->select();
    }

    public function getFlagIdByFlagId(int $flagId): Collection
    {
        $tableName = $this->name . '_flag';
        return $this->name($tableName)->where([
            'flag_id'   => $flagId,
            'is_delete' => config('status.mysql.table_normal')])->select();
    }

    /**
     * @throws Exception
     */
    public function batchUpdateArticleFlagId(array $ids, int $operate, int $flagId): bool
    {
        $tableName = $this->name . '_flag';
        try {
            $this->startTrans();

            // 设置
            if ($operate == 1) {
                $oldArticleFlags    = $this->name($tableName)->where([['aid', 'in', $ids], 'is_delete' => config('status.mysql.table_normal')])->select()->toArray();
                $oldArticleFlagInfo = [];
                foreach ($oldArticleFlags as $old) {
                    $oldArticleFlagInfo[$old['aid']] [] = $old['flag_id'];
                }

                foreach ($ids as $id) {
                    if (isset($oldArticleFlagInfo[$id]) && in_array($flagId, $oldArticleFlagInfo[$id])) {
                        continue;
                    }
                    $this->name($tableName)->insert([
                        'aid'        => $id,
                        'flag_id'    => $flagId,
                        'is_delete'  => config('status.mysql.table_normal'),
                        'created_at' => date('Y-m-d H:i:s'),
                        'updated_at' => date('Y-m-d H:i:s'),
                    ]);
                }
            }

            // 删除
            if ($operate == 2) {
                $this->name($tableName)
                    ->where([['aid', 'in', $ids], 'flag_id' => $flagId])
                    ->update([
                        'is_delete'  => config('status.mysql.table_delete'),
                        'updated_at' => date('Y-m-d H:i:s'),
                    ]);
            }

            $this->commit();
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    public function getPrevAndNextArticle(int $sort, array $where): array
    {
        $prevArticle = $this->where($where)->where([['sort', '<', $sort], 'is_delete' => config('status.mysql.table_normal')])->order('sort asc')->limit(1)->find();
        $nextArticle = $this->where($where)->where([['sort', '>', $sort], 'is_delete' => config('status.mysql.table_normal')])->order('sort desc')->limit(1)->find();
        return ['prev' => $prevArticle, 'next' => $nextArticle];
    }

    public function getArticleRelationAttributes(array $aids): Collection
    {
        $tableName = $this->name . '_relation_attribute';
        return $this->name($tableName)->where(['is_delete' => config('status.mysql.table_normal'), ['aid', 'in', $aids]])->select();
    }

    public function getArticleImages(string $cdnDomain, array $aids): array
    {
        $imageTableName = $this->name . '_image';
        $articleImages  = $this->name($imageTableName)->where([['aid', 'in', $aids], 'is_delete' => config('status.mysql.table_normal')])->select()->toArray();

        $images = [];
        foreach ($articleImages as $k => $articleImage) {
            $images[$articleImage['aid']][] = array_merge(
                $articleImage,
                ['fullImage' => $articleImage['image'] ? $cdnDomain . '/' . $articleImage['image'] : '']
            );
        }

        return $images;
    }
}
